Cancelling coroutine execution
|
val job = launch {
repeat(1000) { i ->
println("job: I'm sleeping $i ...")
delay(500L)
}
}
delay(1300L) // delay a bit
println("main: I'm tired of waiting!")
job.cancel() // cancels the job
job.join() // waits for job's completion
println("main: Now I can quit.")
|
let job = launch {
repeat(1000) { i ->
print("job: I'm sleeping $i ...")
delay(500L)
}
}
delay(1300L) // delay a bit
print("main: I'm tired of waiting!")
job.cancel() // cancels the job
job.join() // waits for job's completion
print("main: Now I can quit.")
|
Cancellation is cooperative
|
val startTime = System.currentTimeMillis()
val job = launch(Dispatchers.Default) {
var nextPrintTime = startTime
var i = 0
while (i < 5) { // computation loop, just wastes CPU
// print a message twice a second
if (System.currentTimeMillis() >= nextPrintTime) {
println("job: I'm sleeping ${i++} ...")
nextPrintTime += 500L
}
}
}
delay(1300L) // delay a bit
println("main: I'm tired of waiting!")
job.cancelAndJoin() // cancels the job and waits for its completion
println("main: Now I can quit.")
|
let startTime = System.currentTimeMillis()
let job = launch(Dispatchers.Default) {
var nextPrintTime = startTime
var i = 0
while (i < 5) { // computation loop, just wastes CPU
// print a message twice a second
if (System.currentTimeMillis() >= nextPrintTime) {
print("job: I'm sleeping ${i++} ...")
nextPrintTime += 500L
}
}
}
delay(1300L) // delay a bit
print("main: I'm tired of waiting!")
job.cancelAndJoin() // cancels the job and waits for its completion
print("main: Now I can quit.")
|
Making computation code cancellable
|
val startTime = System.currentTimeMillis()
val job = launch(Dispatchers.Default) {
var nextPrintTime = startTime
var i = 0
while (isActive) { // cancellable computation loop
// print a message twice a second
if (System.currentTimeMillis() >= nextPrintTime) {
println("job: I'm sleeping ${i++} ...")
nextPrintTime += 500L
}
}
}
delay(1300L) // delay a bit
println("main: I'm tired of waiting!")
job.cancelAndJoin() // cancels the job and waits for its completion
println("main: Now I can quit.")
|
let startTime = System.currentTimeMillis()
let job = launch(Dispatchers.Default) {
var nextPrintTime = startTime
var i = 0
while (isActive) { // cancellable computation loop
// print a message twice a second
if (System.currentTimeMillis() >= nextPrintTime) {
print("job: I'm sleeping ${i++} ...")
nextPrintTime += 500L
}
}
}
delay(1300L) // delay a bit
print("main: I'm tired of waiting!")
job.cancelAndJoin() // cancels the job and waits for its completion
print("main: Now I can quit.")
|
Closing resources with finally
|
val job = launch {
try {
repeat(1000) { i ->
println("job: I'm sleeping $i ...")
delay(500L)
}
} finally {
println("job: I'm running finally")
}
}
delay(1300L) // delay a bit
println("main: I'm tired of waiting!")
job.cancelAndJoin() // cancels the job and waits for its completion
println("main: Now I can quit.")
|
let job = launch {
try {
repeat(1000) { i ->
print("job: I'm sleeping $i ...")
delay(500L)
}
} finally {
print("job: I'm running finally")
}
}
delay(1300L) // delay a bit
print("main: I'm tired of waiting!")
job.cancelAndJoin() // cancels the job and waits for its completion
print("main: Now I can quit.")
|
Run non-cancellable block
|
val job = launch {
try {
repeat(1000) { i ->
println("job: I'm sleeping $i ...")
delay(500L)
}
} finally {
withContext(NonCancellable) {
println("job: I'm running finally")
delay(1000L)
println("job: And I've just delayed for 1 sec because I'm non-cancellable")
}
}
}
delay(1300L) // delay a bit
println("main: I'm tired of waiting!")
job.cancelAndJoin() // cancels the job and waits for its completion
println("main: Now I can quit.")
|
let job = launch {
try {
repeat(1000) { i ->
print("job: I'm sleeping $i ...")
delay(500L)
}
} finally {
withContext(NonCancellable) {
print("job: I'm running finally")
delay(1000L)
print("job: And I've just delayed for 1 sec because I'm non-cancellable")
}
}
}
delay(1300L) // delay a bit
print("main: I'm tired of waiting!")
job.cancelAndJoin() // cancels the job and waits for its completion
print("main: Now I can quit.")
|
Timeout
|
withTimeout(1300L) {
repeat(1000) { i ->
println("I'm sleeping $i ...")
delay(500L)
}
}
|
withTimeout(1300L) {
repeat(1000) { i ->
print("I'm sleeping $i ...")
delay(500L)
}
}
|
val result = withTimeoutOrNull(1300L) {
repeat(1000) { i ->
println("I'm sleeping $i ...")
delay(500L)
}
"Done" // will get cancelled before it produces this result
}
println("Result is $result")
|
let result = withTimeoutOrNull(1300L) {
repeat(1000) { i ->
print("I'm sleeping $i ...")
delay(500L)
}
"Done" // will get cancelled before it produces this result
}
print("Result is $result")
|
Asynchronous timeout and resources
|
var acquired = 0
class Resource {
init { acquired++ } // Acquire the resource
fun close() { acquired-- } // Release the resource
}
fun main() {
runBlocking {
repeat(100_000) { // Launch 100K coroutines
launch {
val resource = withTimeout(60) { // Timeout of 60 ms
delay(50) // Delay for 50 ms
Resource() // Acquire a resource and return it from withTimeout block
}
resource.close() // Release the resource
}
}
}
// Outside of runBlocking all coroutines have completed
println(acquired) // Print the number of resources still acquired
}
|
var acquired = 0
class Resource {
init { acquired++ } // Acquire the resource
func close() { acquired-- } // Release the resource
}
func main() {
runBlocking {
repeat(100_000) { // Launch 100K coroutines
launch {
let resource = withTimeout(60) { // Timeout of 60 ms
delay(50) // Delay for 50 ms
Resource() // Acquire a resource and return it from withTimeout block
}
resource.close() // Release the resource
}
}
}
// Outside of runBlocking all coroutines have completed
print(acquired) // Print the number of resources still acquired
}
|
runBlocking {
repeat(100_000) { // Launch 100K coroutines
launch {
var resource: Resource? = null // Not acquired yet
try {
withTimeout(60) { // Timeout of 60 ms
delay(50) // Delay for 50 ms
resource = Resource() // Store a resource to the variable if acquired
}
// We can do something else with the resource here
} finally {
resource?.close() // Release the resource if it was acquired
}
}
}
}
// Outside of runBlocking all coroutines have completed
println(acquired) // Print the number of resources still acquired
|
runBlocking {
repeat(100_000) { // Launch 100K coroutines
launch {
var resource: Resource? = null // Not acquired yet
try {
withTimeout(60) { // Timeout of 60 ms
delay(50) // Delay for 50 ms
resource = Resource() // Store a resource to the variable if acquired
}
// We can do something else with the resource here
} finally {
resource?.close() // Release the resource if it was acquired
}
}
}
}
// Outside of runBlocking all coroutines have completed
print(acquired) // Print the number of resources still acquired
|